#include <buola/gui.h>

#include <buola/io/cresourcefinder.h>

#include <buola/image/cimage.h>
#include <buola/utility/cregion.h>
#include <buola/image/cgc.h>

#include <buola/widgets/cgrip.h>

namespace buola { namespace gui {

img::CPicture CGrip::mGrip;

CGrip::CGrip()
{
    mDragging=false;
    mPosIsValid=false;
    mPointer=CPointer::STOCK_NOSTOCK;

    if(!mGrip)
        mGrip=img::CPicture(io::data_finder().FindFile("buola/images/grip.png"));
    
    SetBackNone();
}

CGrip::~CGrip()
{
}

inline void CGrip::CalcPos()
{
    mPos[0]={0,0};
    mPos[1]={Size().x/2-4,0};
    mPos[2]={Size().x-8,0};
    mPos[3]={0,Size().y/2-4};
    mPos[4]={Size().x-8,Size().y/2-4};
    mPos[5]={0,Size().y-8};
    mPos[6]={Size().x/2-4,Size().y-8};
    mPos[7]={Size().x-8,Size().y-8};
    
    CRegion lRegion;

    for(int i=0;i<8;i++)
    {
        lRegion|=CRect_d(mPos[i].x+1,mPos[i].y,mPos[i].x+7,mPos[i].y+1);
        lRegion|=CRect_d(mPos[i].x,mPos[i].y+1,mPos[i].x+8,mPos[i].y+7);
        lRegion|=CRect_d(mPos[i].x+1,mPos[i].y+7,mPos[i].x+7,mPos[i].y+8);
    }

    ///\todo SetShape(lRegion);

    mPosIsValid=true;
}

void CGrip::UpdatePointer(const CPoint_d &pPoint)
{
    CPointer::EStock lPointer=CPointer::STOCK_NOSTOCK;
    
    int lPos=HitTest(pPoint);

    if(lPos==0||lPos==7)
    {
        lPointer=CPointer::STOCK_SIZENWSE;
    }
    else if(lPos==1||lPos==6)
    {
        lPointer=CPointer::STOCK_SIZENS;
    }
    else if(lPos==2||lPos==5)
    {
        lPointer=CPointer::STOCK_SIZENESW;
    }
    else if(lPos==3||lPos==4)
    {
        lPointer=CPointer::STOCK_SIZEWE;
    }
    
    if(lPointer==mPointer) return;

    mPointer=lPointer;
    SetPointer(mPointer);
}

int CGrip::HitTest(const CPoint_d &pPoint)
{
    for(int i=0;i<8;i++)
    {
        CRect_d lRect(mPos[i].x,mPos[i].y,mPos[i].x+8,mPos[i].y+8);

        if(lRect.Contains(pPoint))
            return i;
    }   
    
    return -1;
}

///////////////// events //////////////////

void CGrip::OnExpose(const CExposeEvent &pE)
{
    if(!mPosIsValid)
    {
        CalcPos();
    }

    for(int i=0;i<8;i++)
    {
        pE.mGC->DrawImage(mPos[i],mGrip);
    }
}

void CGrip::OnButtonDown(const CMouseEvent &pE)
{
    if(pE.mButton!=EMouseButton::LEFT) return;

    mDragType=HitTest(pE.mPoint);
    if(mDragType<0) return;

    mDragging=true;
    mDragPos=pE.mPoint-mPos[mDragType];
}

void CGrip::OnButtonUp(const CMouseEvent &pE)
{
    if(pE.mButton!=EMouseButton::LEFT) return;

    mDragging=false;
}
 
void CGrip::OnMouseMove(const CMouseEvent &pE)
{
    if(mDragging)
    {
        CPoint_d lDiff=pE.mPoint-mDragPos-mPos[mDragType];
        CPoint_d lMove(0,0);
        CSize_d lSize(0,0);
        
        switch(mDragType)
        {
        case GRIP_NORTHWEST:
            lMove=lDiff;
            lSize={-lDiff.x,-lDiff.y};
            break;
        case GRIP_NORTH:
            lMove={0,lDiff.y};
            lSize={0,-lDiff.y};
            break;
        case GRIP_NORTHEAST:
            lMove={0,lDiff.y};
            lSize={lDiff.x,-lDiff.y};
            break;
        case GRIP_WEST:
            lMove={lDiff.x,0};
            lSize={-lDiff.x,0};
            break;
        case GRIP_EAST:
            lSize={lDiff.x,0};
            break;
        case GRIP_SOUTHWEST:
            lMove={lDiff.x,0};
            lSize={-lDiff.x,lDiff.y};
            break;
        case GRIP_SOUTH:
            lSize={0,lDiff.y};
            break;
        case GRIP_SOUTHEAST:
            lSize={lDiff.x,lDiff.y};
            break;
        default:
            return;
        }
        eMoved(lMove,lSize,pE.mMods);
        UpdatePointer(pE.mPoint);
    }
}

void CGrip::OnMouseIn(const CMouseEvent &pE)
{
    UpdatePointer(pE.mPoint);
}

void CGrip::OnMouseOut(const CMouseEvent &pE)
{
}

void CGrip::OnFocusIn(const CFocusEvent &pE)
{
}

void CGrip::OnFocusOut(const CFocusEvent &pE)
{
}

void CGrip::OnKeyDown(const CKeyEvent &pE)
{
    ///\todo
/*  if(mStyle&STYLE_DISABLED) return;
    if(pE->mKey==KEY_SPACE)
    {
        mPressed=true;
        mInside=true;
        Refresh();
    }
*/
}

void CGrip::OnKeyUp(const CKeyEvent &pE)
{
}

void CGrip::OnStyleChanged(TStyle)
{
/*
    int lChange=pOld^mStyle;
    
    if(lChange&STYLE_DISABLED)
    {
        if(mStyle&STYLE_DISABLED)
        {
            mPressed=false;
            mInside=false;
        }
        Refresh();
    }
    if(lChange&STYLE_FAKE)
    {
        if(mStyle&STYLE_FAKE)
        {
            SetInputMode(INPUT_MOUSETRANSPARENT);
        }
        else
        {
            SetInputMode(INPUT_NORMAL);
        }
    }
*/
}

void CGrip::OnSize(const CGeometryEvent &pE)
{
    mPosIsValid=false;
}

void CGrip::OnMove(const CGeometryEvent &pE)
{
//  if(mDragging)
//  {
//      mDragPos=GetMousePos();
//  }
}

/*namespace gui*/ } /*namespace buola*/ }
